package com.groupbuying.redpacket.intercepter;

import com.groupbuying.redpacket.bo.RedPacketLimitBO;
import com.groupbuying.redpacket.constants.RedisConstans;
import com.groupbuying.redpacket.context.FilterContextHandler;
import com.groupbuying.redpacket.dao.RedPacketListDao;
import com.groupbuying.redpacket.utils.JSONUtils;
import com.groupbuying.redpacket.utils.RedisUtils;
import com.groupbuying.redpacket.utils.apiresult.ApiResult;
import com.groupbuying.redpacket.utils.apiresult.ApiResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;

public class RedPacketIntercepter extends HandlerInterceptorAdapter {
    private static final Logger logger = LoggerFactory.getLogger(RedPacketIntercepter.class);
    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private RedPacketListDao redPacketListDao;

    @Value("${redPacket.eventId}")
    private String eventId;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String userId = FilterContextHandler.getUserID();

        Object task = redisUtils.getValue(eventId);
        if (task == null) {
            //TODO 活动未开始
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.ACTIVITY_NOT_STARTED)));
            return false;
        }

        //防止很简短的时间重复提交
        String userLock = RedisConstans.USER_LOCK + userId;
        boolean ret = redisUtils.setIfAbsent(userLock, userId, RedisConstans.USER_LOCK_EXP);
        if (!ret) {
            //回执未中奖
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json;charset=UTF-8");
            //未中奖
            response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.NOT_WINNING)));
            return false;
        }


        try {
            RedPacketLimitBO taskObject = (RedPacketLimitBO) task;
            //当前活动所有轮次限制抽奖金额
            BigDecimal curActivityLimitAmount = taskObject.getSingleLimitAmount();
            //当前活动所有轮次限制抽奖次数
            Integer curActivityLimitCount = taskObject.getSingleLimitCounts();
            //当前轮次是否限制抽奖金额
            Integer curTaskIsLimitAmount = taskObject.getIsAmountLimit();
            //当前轮次是否限制抽奖次数
            Integer curTaskIsLimitCount = taskObject.getIsCountLimit();
            //当前轮次限制抽奖金额
            BigDecimal curTaskLimitAmount = taskObject.getRandomLimitAmount();
            //当前轮次限制抽奖次数
            Integer curTaskLimitCount = taskObject.getRandomLimitCounts();
            //当前执行的任务ID
            Long taskId = taskObject.getTaskId();
            //当前任务所属的活动ID
            String activityId = taskObject.getActivityId();
            //持续时间
            Integer keepTime = taskObject.getKeepTime();
            //红包总数
            Integer redPacketsCounts = taskObject.getTotalRedPacketCount();


            //TODO 判断当前用户是否满足该活动分类下的抽奖限制
            int curActivityCount = 0;
            BigDecimal curActivityAmount = new BigDecimal("0");
            //查询当前用户在当前的活动类型下面所有的中奖记录信息
            Map<String, Object> activityResult = redPacketListDao.winNumberWinAmountByUserIdPlatFrom(activityId, userId);
            //当前用户整个活动分类已经中间次数
            curActivityCount = Integer.valueOf(activityResult.get("winNumber").toString());
            //当前用户整个活动分类已经中奖金额
            curActivityAmount = (BigDecimal) activityResult.get("winAmount");
            //用户中奖金额超过或者等于整个活动分类的限制金额 直接返回未中奖
            if (curActivityAmount.compareTo(curActivityLimitAmount) != -1) {
                //回执未中奖
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json;charset=UTF-8");
                //未中奖
                response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.NOT_WINNING)));
                //删除用户锁
                redisUtils.delKey(userLock);
                return false;
            }
            //用户中奖次数超过或者等于整个活动分类的限制金额， 直接返回未中奖
            if (curActivityCount >= curActivityLimitCount) {
                //回执未中奖
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json;charset=UTF-8");
                //未中奖
                response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.NOT_WINNING)));
                //删除用户锁
                redisUtils.delKey(userLock);
                return false;
            }


            //TODO 判断当前用户是否满足该轮次抽奖限制
            int curTaskCount = 0;
            BigDecimal curTaskAmount = new BigDecimal("0");
            //当前轮次单人限制抽奖金额
            if (1 == curTaskIsLimitAmount) {
                //1、TODO 查询当前用户这个活动、这个轮次已经中奖的金额
                //2、TODO 和限制的抽奖金额做比较（大于等于直接返回未中奖或者金额超限）
                //此处使用CustomerId作为查询的主要参数，考虑到用户手机号作为唯一验证需要用手机号做统一查询
                Map<String, Object> result = redPacketListDao.winNumberWinAmount(taskId.toString(), userId);
                //当前用户本轮已经中间次数
                curTaskCount = Integer.valueOf(result.get("winNumber").toString());
                //当前用户本轮已经中奖金额
                curTaskAmount = (BigDecimal) result.get("winAmount");
                //在缓存中放入当前用户本轮次中奖金额
                FilterContextHandler.set("taskCurrentAmount", curTaskAmount);
                //用户中奖金额超过或者等于限制金额 直接返回未中奖
                if (curTaskAmount.compareTo(curTaskLimitAmount) != -1) {
                    //回执未中奖
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/json;charset=UTF-8");
                    //未中奖
                    response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.NOT_WINNING)));
                    //删除用户锁
                    redisUtils.delKey(userLock);
                    return false;
                }
            }
            //单人限制抽奖次数
            if (1 == curTaskIsLimitCount) {
                //1、TODO 查询当前用户这个活动、这个轮次已经中奖的次数
                //2、TODO 和限制的抽奖次数做比较（大于等于直接返回未中奖或者次数超限）
                if (curTaskLimitCount <= curTaskCount) {
                    //回执未中奖
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/json;charset=UTF-8");
                    //未中奖
                    response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.NOT_WINNING)));
                    //删除用户锁
                    redisUtils.delKey(userLock);
                    return false;
                }
            }

            //奖池已清空
            if (redisUtils.sGetSetSize(eventId + taskId) == 0) {
                //回执未中奖
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json;charset=UTF-8");
                //未中奖
                response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.NOT_WINNING)));
                //删除用户锁
                redisUtils.delKey(userLock);
                return false;
            }


            //TODO 这个地方做红包线性分布处理
            //剩余红包数量
            Long curRemainCount = redisUtils.sGetSetSize(eventId + taskId);
            //剩余过期时间
            Long curRemainTime = redisUtils.getExpireMilliSeconds(eventId);

            //按照最后10秒的时间不做限制判断
            if (curRemainTime > 5000L) {
                //如果红包总数和时间均值 大于 当前的实际均值 证明 现在红包发多了
                BigDecimal original = new BigDecimal(redPacketsCounts).divide(new BigDecimal(keepTime * 1000), 16, RoundingMode.HALF_DOWN);
                BigDecimal now = new BigDecimal(curRemainCount).divide(new BigDecimal(curRemainTime), 16, RoundingMode.HALF_DOWN);
                if (original.compareTo(now) == 1) {
                    //回执未中奖
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/json;charset=UTF-8");
                    //未中奖
                    response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.NOT_WINNING)));
                    //删除用户锁
                    redisUtils.delKey(userLock);
                    return false;
                }

            }

            //TODO 将当前活动及任务的限制信息放入缓存中
            // 整个活动限制金额
            FilterContextHandler.set("curActivityLimitAmount", curActivityLimitAmount);
            //当前用户活动累计金额
            FilterContextHandler.set("curActivityAmount", curActivityAmount);
            //当前任务的限制金额
            FilterContextHandler.set("curTaskLimitAmount", curTaskLimitAmount);
            //当前用户任务的累计金额
            FilterContextHandler.set("curTaskAmount", curTaskAmount);
            //任务ID
            FilterContextHandler.set("taskId", taskId);
            //活动ID
            FilterContextHandler.set("activityId", activityId);
            //持续时间
            FilterContextHandler.set("keepTime", keepTime);
            //红包数量
            FilterContextHandler.set("redPacketsCounts", redPacketsCounts);
            //活动名称+任务名称
            FilterContextHandler.set("activityTaskName", taskObject.getActivityName());
        } catch (Exception e) {
            //删除用户锁
            redisUtils.delKey(userLock);
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json;charset=UTF-8");
            //未中奖
            response.getWriter().print(JSONUtils.beanToJson(ApiResult.failure(ApiResultCode.NOT_WINNING)));
            return false;
        }

        return super.preHandle(request, response, handler);
    }

}
